/*
 * FL7703 LCD程序，集成LVGL并使用ESP LVGL端口
 * 更新时间: 2024-12-19
 */

#include "soc/soc_caps.h"

#if SOC_MIPI_DSI_SUPPORTED

#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_io.h"
#include "esp_ldo_regulator.h"
#include "esp_lcd_mipi_dsi.h"
#include "esp_lcd_fl7703.h"
#include "lvgl.h"
#include "esp_lvgl_port.h"
#include "lv_demos.h"

// LCD 配置参数
#define LCD_H_RES                       (720)
#define LCD_V_RES                       (720)
#define LCD_BIT_PER_PIXEL               (16)
#define LCD_DRAW_BUFF_SIZE              (LCD_H_RES * 50)  // 增加缓冲区大小减少闪屏

// GPIO引脚定义
#define PIN_NUM_LCD_RST                 (24)
#define PIN_NUM_BK_LIGHT                (29)
#define LCD_BK_LIGHT_ON_LEVEL           (1)

// MIPI DSI PHY 电源配置
#define MIPI_DSI_PHY_PWR_LDO_CHAN       (3)
#define MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV (2500)

static const char *TAG = "fl7703_lvgl";

/**
 * @brief 初始化背光GPIO
 */
static void init_backlight(void)
{
    gpio_config_t bk_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << PIN_NUM_BK_LIGHT
    };
    ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
    ESP_ERROR_CHECK(gpio_set_level(PIN_NUM_BK_LIGHT, LCD_BK_LIGHT_ON_LEVEL));
    ESP_LOGI(TAG, "背光已开启");
}

/**
 * @brief 初始化MIPI DSI PHY电源
 */
static esp_ldo_channel_handle_t init_mipi_dsi_power(void)
{
    esp_ldo_channel_handle_t ldo_mipi_phy = NULL;
    esp_ldo_channel_config_t ldo_mipi_phy_config = {
        .chan_id = MIPI_DSI_PHY_PWR_LDO_CHAN,
        .voltage_mv = MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV,
    };
    ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy));
    ESP_LOGI(TAG, "MIPI DSI PHY电源已开启");
    return ldo_mipi_phy;
}

/**
 * @brief 初始化MIPI DSI总线
 */
static esp_lcd_dsi_bus_handle_t init_mipi_dsi_bus(void)
{
    esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL;
    esp_lcd_dsi_bus_config_t bus_config = FL7703_PANEL_BUS_DSI_2CH_CONFIG();
    ESP_ERROR_CHECK(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus));
    ESP_LOGI(TAG, "MIPI DSI总线初始化完成");
    return mipi_dsi_bus;
}

/**
 * @brief 初始化LCD面板IO
 */
static esp_lcd_panel_io_handle_t init_panel_io(esp_lcd_dsi_bus_handle_t dsi_bus)
{
    esp_lcd_panel_io_handle_t mipi_dbi_io = NULL;
    esp_lcd_dbi_io_config_t dbi_config = FL7703_PANEL_IO_DBI_CONFIG();
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_dbi(dsi_bus, &dbi_config, &mipi_dbi_io));
    ESP_LOGI(TAG, "面板IO初始化完成");
    return mipi_dbi_io;
}

/**
 * @brief 初始化FL7703 LCD面板
 */
static esp_lcd_panel_handle_t init_lcd_panel(esp_lcd_panel_io_handle_t io, esp_lcd_dsi_bus_handle_t dsi_bus)
{
    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_dpi_panel_config_t dpi_config = FL7703_720_720_PANEL_CONFIG();
    dpi_config.num_fbs = 2;  // 使用双缓冲以优化性能
    
    // 使用库提供的默认FL7703NI配置
    fl7703_vendor_config_t vendor_config = FL7703_VENDOR_CONFIG_DEFAULT(dsi_bus, &dpi_config);

    const esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = PIN_NUM_LCD_RST,
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
        .bits_per_pixel = LCD_BIT_PER_PIXEL,
        .vendor_config = &vendor_config,
    };

    ESP_ERROR_CHECK(esp_lcd_new_panel_fl7703(io, &panel_config, &panel_handle));
    ESP_LOGI(TAG, "FL7703面板已创建");

    // 复位和初始化面板
    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
    ESP_LOGI(TAG, "面板复位完成");
    
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
    ESP_LOGI(TAG, "面板初始化完成");
    
    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
    ESP_LOGI(TAG, "显示已开启");

    return panel_handle;
}

/**
 * @brief 初始化LVGL显示
 */
static lv_display_t* init_lvgl_display(esp_lcd_panel_io_handle_t io, esp_lcd_panel_handle_t panel)
{
    // 初始化LVGL端口 - 优化任务配置
    const lvgl_port_cfg_t lvgl_cfg = {
        .task_priority = 4,         // 设置较高优先级减少闪屏
        .task_stack = 6144,         // 增加堆栈大小
        .task_affinity = -1,        // 允许在任意核心运行
        .task_max_sleep_ms = 10,    // 减少休眠时间提高响应性
        .timer_period_ms = 5        // 缩短定时器周期
    };
    ESP_ERROR_CHECK(lvgl_port_init(&lvgl_cfg));
    ESP_LOGI(TAG, "LVGL端口初始化完成");

    // 配置LVGL显示
    const lvgl_port_display_cfg_t disp_cfg = {
        .io_handle = io,
        .panel_handle = panel,
        .control_handle = NULL,
        .buffer_size = LCD_DRAW_BUFF_SIZE,
        .double_buffer = true,           // 启用双缓冲减少闪屏
        .hres = LCD_H_RES,
        .vres = LCD_V_RES,
        .monochrome = false,
        .color_format = LV_COLOR_FORMAT_RGB565,
        .flags = {
            .buff_dma = false,           // 保持禁用DMA避免总线冲突
            .buff_spiram = false,
            .swap_bytes = false,
            .sw_rotate = false,
            .full_refresh = false,        // 启用完整刷新模式减少撕裂
            .direct_mode = false,
        }
    };

    // DSI配置
    const lvgl_port_display_dsi_cfg_t dsi_cfg = {
        .flags = {
            .avoid_tearing = false,  // 防撕裂功能
        }
    };

    lv_display_t *display = lvgl_port_add_disp_dsi(&disp_cfg, &dsi_cfg);
    if (display == NULL) {
        ESP_LOGE(TAG, "添加LVGL显示失败");
        return NULL;
    }
    ESP_LOGI(TAG, "LVGL显示已添加DSI支持");
    return display;
}

/**
 * @brief 启动LVGL演示程序
 */
static void start_lvgl_demo(void)
{
    if (lvgl_port_lock(1000)) {
        ESP_LOGI(TAG, "启动LVGL基准测试演示...");
        lv_demo_benchmark();
        
        // 其他可选的演示程序:
        // lv_demo_stress();     // 压力测试
        
        lvgl_port_unlock();
        ESP_LOGI(TAG, "LVGL演示已启动");
    } else {
        ESP_LOGE(TAG, "获取LVGL锁失败");
    }
}

void app_main(void)
{
    ESP_LOGI(TAG, "FL7703 LVGL演示程序启动 (使用ESP LVGL端口)");

    // 硬件初始化流程
    init_backlight();
    esp_ldo_channel_handle_t ldo_handle = init_mipi_dsi_power();
    esp_lcd_dsi_bus_handle_t dsi_bus = init_mipi_dsi_bus();
    esp_lcd_panel_io_handle_t panel_io = init_panel_io(dsi_bus);
    esp_lcd_panel_handle_t panel = init_lcd_panel(panel_io, dsi_bus);

    // LVGL初始化
    lv_display_t *display = init_lvgl_display(panel_io, panel);
    if (display == NULL) {
        ESP_LOGE(TAG, "LVGL显示初始化失败");
        return;
    }

    // 启动演示程序
    start_lvgl_demo();

    // 主循环 - 监控系统状态
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(10000));
        ESP_LOGI(TAG, "FL7703 LVGL运行中... 可用堆内存: %lu 字节", 
                (unsigned long)esp_get_free_heap_size());
    }
}

#endif 